![]() |
![]() |
|
in Ihrem Programmcode geschrieben, beispielsweise im Click-Ereignis einer Schaltfläche, fühlt sich der Drucker bereits angesprochen und druckt ein leeres Blatt Papier aus. Woher soll der Drucker auch wissen, was er zu Papier bringen soll? Die Steuerung des Dokumentenausdrucks erfolgt über vier Ereignisse des PrintDocument-Objekts:
23.2.3 Die Ereignisse »BeginPrint« und »EndPrint«
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Eigenschaft | Beschreibung |
| Cancel | Ermöglicht den Abbruch der Operation. |
| PrintAction | Beschreibt das Ziel des Druckvorgangs. Die Eigenschaft ist vom Typ PrintAction. |
PrintAction ist vom Typ der gleichnamigen Enumeration, deren Mitglieder Sie der folgenden Tabelle entnehmen können.
| Member | Beschreibung |
| PrintToFile | Es wird in eine Datei gedruckt. |
| PrintToPreview | Die Druckoperation hat die Druckvorschau zum Ziel. |
| PrintToPrinter | Es wird auf einem Drucker gedruckt. |
Das Objekt QueryPageSettingsEventArgs, das dieses Ereignis an den Ereignishandler sendet, enthält nur die drei Eigenschaften Cancel zum Abbruch des Druckvorgangs, PrintAction zum Beschreiben des Ausgabeziels sowie PageSettings. Letztere stellt die Referenz auf ein gleichnamiges Objekt bereit, mit dem die Einstellungen der zu druckenden Seite festgelegt werden. QueryPageSettingsEventArgs spielt nur dann eine Rolle, wenn mehrere zu druckende Seiten mit anderen Seiteneinstellungen ausgedruckt werden sollen.
| Eigenschaft | Beschreibung |
| Cancel | Ermöglicht den Abbruch der Operation. |
| PageSettings | Beschreibt die Seiteneinstellung der aktuellen Seite. |
| PrintAction | Beschreibt das Ziel des Druckvorgangs. Die Eigenschaft ist vom Typ PrintAction. |
Zweifelsfrei ist das Ereignis PagePrint das wichtigste eines Druckjobs, denn in diesem Ereignis wird festgelegt, was der Drucker zu Papier bringen soll. Der Ereignishandler erhält vom Ereignis ein Objekt vom Typ PrintPageEventArgs, in dem sechs Eigenschaften definiert sind, die für den Ausdruck von wesentlicher Bedeutung sind:
| Eigenschaft | Beschreibung |
| Cancel | Abbruch des Druckauftrags. |
| Graphics | Ist das Graphics-Objekt zum Zeichnen der Seite. Die Eigenschaft ist schreibgeschützt. |
| HasMorePages | Gibt an, ob noch mehr Seiten gedruckt werden sollen. |
| MarginBounds | Ruft den rechteckigen Bereich ab, der den innerhalb der Seitenränder liegenden Teil der Seite darstellt. Die Eigenschaft ist schreibgeschützt. |
| PageBounds | Ruft den rechteckigen Bereich ab, der die Gesamtfläche der Seite darstellt. Die Eigenschaft ist schreibgeschützt. |
| PageSettings | Beschreibt die Seiteneinstellung der aktuellen Seite. Die Eigenschaft ist schreibgeschützt. |
| Hinweis |
|
Für jede zu druckende Seite werden die beiden Ereignisse QueryPageSettings und PrintPage ausgelöst. |
|
Falls es Sie irritieren sollte, dass beide eine Eigenschaft PageSettings bereitstellen, beachten Sie bitte, dass diese Eigenschaft nur in QueryPageSettings geändert werden kann und in PrintPage schreibgeschützt ist. |
Der Aufruf der Print-Methode bewirkt das Durchlaufen der Ereigniskette des PrintDocument-Objekts. Sie werden in jedem Fall das PrintPage-Ereignis codieren müssen, um den Drucker mit den notwendigen Informationen des Druckvorgangs zu versorgen. Hierbei spielt das vom Parameter PrintPageEventArgs übergebene Graphics-Objekt die Schlüsselrolle. Es ist vergleichbar mit dem Graphics-Objekt, das vom Paint-Ereignis oder über CreateGraphics bereitgestellt wird, jedoch dient es dazu, Methoden aufzurufen, um Grafiken auf dem Drucker auszugeben (oder möglicherweise auch zu einem anderen Empfänger zu senden, beispielsweise einer Datei). Die Standardmaßeinheit ist GraphicsUnit.Display, also entspricht eine Einheit 1/100 Zoll. Das werden Sie vermutlich nur wenig gut gebrauchen können. Daher empfiehlt es sich, mit
| g.PageUnit = GraphicsUnit.Millimeter |
auf das metrische System umzustellen. »g« ist in diesem Fall die Referenz auf das Graphics-Objekt.
| Hinweis |
|
Für jede zu druckende Seite wird das Ereignis PrintPage erneut ausgelöst. Das hat weitergehende Konsequenzen, denn damit wird auch jedes Mal ein neues Graphics-Objekt erstellt. Wenn Sie eine Graphics-Einstellung für eine Druckseite vornehmen, wird diese nicht von der nächsten zu druckenden Seite übernommen. Deshalb müssen Sie die Grundeinstellungen von Graphics für jede weitere Seite erneut festlegen. |
Die Eigenschaft PageBounds liefert exakt die Abmessungen des zu bedruckenden Papiers.
| Public ReadOnly Property PageBounds As Rectangle |
Fragen Sie Width und Height des zurückgegebenen Rectangle-Objekts ab, erhalten Sie die Abmessungen des entsprechenden Papierformats. Beachten Sie, dass hier die Ausgabe von der Standardeinheit (1/100 Zoll) in das metrische System umgerechnet wird.
PageBounds hat seinen Ursprungspunkt (0, 0) in der linken oberen Ecke. Allerdings entspricht das nicht der linken oberen Ecke der zu bedruckenden Seite, denn wir wissen alle, dass ein Drucker aus technischen Gründen nicht in der Lage ist, bis an den äußersten Rand zu gehen, weil der Randbereich vom Druckkopf des Druckers nicht erreicht wird. Das von PageBounds beschriebene Rechteck ist ein wenig verschoben. Versuche mit mehreren Druckern haben gezeigt, dass die Verschiebung vom Druckertyp abhängt. Im günstigsten Fall blieb bei den Versuchen ein nicht bedruckbarer Streifen von rundum ca. 4 mm.
Den äußersten Rand ausreizen zu wollen, wird zu abgeschnittenen Druckergebnissen führen. Daher wird von der Eigenschaft MarginBounds des PrintPageEventArgs-Objekts ein anderes, bedruckbares Rechteck beschrieben, das als Vorgabe rundum 100 Einheiten (also 2,54 cm) Randbreite für den Druckbereich festlegt. Positionieren Sie die Ausgabe mit MarginBounds, wird das allerdings nicht der tatsächliche Abstand zwischen Papierrand und Druckausgabe sein. Denn zu der Einstellung von MarginBounds muss noch der druckerabhängige freie Randbereich addiert werden.
Der große Nachteil der Eigenschaft MarginBounds ist, dass der genutzte Druckbereich deutlich kleiner ist als der, der tatsächlich zur Verfügung steht. Wir haben noch eine weitere Alternative. Das Graphics-Objekt stellt mit seiner Eigenschaft VisibleClipBounds ein Rechteck vom Typ RectangleF bereit, das den sichtbaren Bereich des Graphics-Objekts mit seinen Eigenschaften X, Y, Width und Height beschreibt:
| Public ReadOnly Property VisibleClipBounds As RectangleF |
Auch VisibleClipBounds arbeitet mit einer Unbekannten, und das ist das Verhältnis der Aufteilung der unbedruckbaren Ränder. Sie müssen sich das von dieser Eigenschaft zurückgelieferte Rechteck wie ein Fenster vorstellen, das über dem Papier zentral positioniert wird. Die Folge davon ist, dass die Breite des linken und rechten unbedruckbaren Rands gleich ist, analog die Breite des unbedruckbaren oberen und unteren Rands. In Abhängigkeit vom eingesetzten Druckermodell muss das Verhältnis aber nicht 1:1 sein und kann mehr oder weniger stark zuungunsten eines der beiden Seitenränder ausfallen.
Im folgenden Programmbeispiel werden die Eigenschaften PageBounds und MarginBounds demonstriert sowie die Abhängigkeit der Darstellung von der Einstellung PageUnit.
| ' ---------------------------------------------------------- |
| ' Beispiel: ...\Kapitel 23\Seitenränder |
| ' ---------------------------------------------------------- |
| Public Class Form1 |
| Private Sub btnDrucken_Click(...) Handles btnDrucken.Click |
| PrintDocument1.Print() |
| End Sub |
| Private Sub PrintDocument1_PrintPage(ByVal sender As Object, _ |
| ByVal e As PrintPageEventArgs) _ |
| Handles PrintDocument1.PrintPage |
| Dim g As Graphics = e.Graphics |
| ' g.PageUnit = GraphicsUnit.Millimeter |
| Dim p As Pen = New Pen(Brushes.Black, 3) |
| ' Rechtecke zeichnen |
| g.DrawRectangle(p, e.MarginBounds.X, _ |
| e.MarginBounds.Y, 100, 100) |
| g.DrawRectangle(p, e.PageBounds.Left, e.PageBounds.Top, _ |
| e.PageBounds.Width, e.PageBounds.Height) |
| End Sub |
| End Class |
Das Programm zeichnet ein Rechteck und ein Quadrat. Beachten Sie, dass die Anweisung zur Umstellung auf das metrische System zunächst auskommentiert ist. Mit dieser Einstellung wird die erste gezeichnete Figur, das Rechteck, oben und links die Grenzen des druckerspezifischen Druckbereichs einhalten. Weil die Höhe und Breite des zu zeichnenden Rechtecks den Abmessungen des Papierformats entsprechen, kann das Rechteck jedoch nicht vollständig gezeichnet werden.
Das Quadrat hat eine Kantenlänge von 100. Das entspricht 100 Einheiten zu je 1/100 Zoll, also 2,54 cm. Sie können das auf Ihrem Ausdruck nachmessen. Der Abstand zum linken und rechten Rand ist mit e.MarginBounds.X und e.MarginBounds.Y angegeben. MarginBounds hat die Vorgabe von 1 Zoll, also 2,54 cm. Sie können auch dieses Maß auf Ihrem Ausdruck nachmessen, es ist der Abstand zu der linken bzw. oberen Kante des Rechtecks, das bekanntlich den möglichen Druckbereich voll ausgereizt hat.
Heben Sie nun die Auskommentierung von
| g.PageUnit = GraphicsUnit.Millimeter |
auf, und starten Sie das Programm erneut. Sie werden sehen, dass sich an der Position des Rechtecks nichts geändert hat, da mit der Umstellung auf das metrische Maßsystem keine Änderung des möglichen Druckbereichs einhergeht. Das Quadrat hingegen weist nun nicht mehr einen Abstand von 100 Einheiten zu je 1/100 Zoll zum Rand auf, sondern exakt 100 mm. Die Kantenlänge des Quadrats beträgt ebenfalls 100 mm.
Auffällig ist auch, dass die Strichstärke bei beiden Ausdrucken unterschiedlich ist, die das Pen-Objekt mit 3 vorgibt. Hier wird die Strichstärke entweder als 3 mm oder 3/100 Zoll interpretiert. Deutlich wird bei dem Ausdruck im metrischen System zudem, dass die Strichbreite des Rechtecks nur zur Hälfte ausgegeben wird. Das ist auch verständlich, denn der Bezugspunkt ist immer in Linienmitte zu finden, und die haben wir am äußersten linken und oberen Rand festgelegt.
Das Thema zum Einstellen der Seitenränder ist an dieser Stelle noch nicht beendet, denn das .NET Framework 2.0 hat darüber hinaus eine Neuerung zu bieten, die uns einen vollständigen Ausdruck ohne unbeabsichtigtes Abschneiden praktisch garantiert. Es handelt sich hier um eine Ergänzung der Eigenschaften der Klasse PageSettings, die uns im nächsten Abschnitt über den Weg laufen wird.
PageSettings beschreibt ganz allgemein die Einstellungen einer Druckseite. Ergänzend zu .NET Framework 1.0/1.1 bietet diese Klasse drei zusätzliche Eigenschaften an:
| HardMarginX |
| HardMarginY |
| PrintableArea |
Alle drei Eigenschaften sind schreibgeschützt, denn sie liefern druckerspezifische Werte. HardMarginX und HardMarginY beschreiben den Abstand vom linken bzw. oberen Seitenrand. Als Seitenrand dürfen Sie jedoch nicht den Rand des physischen Ausdrucks verstehen, es ist vielmehr der äußerste vom Druckkopf ansteuerbare Rand. PrintableArea ruft mit den Eigenschaften Width und Height den bedruckbaren Bereich ab. Wenn Sie das Beispielprogramm Seitenränder um
| g.DrawRectangle(p, e.PageSettings.HardMarginY, |
| e.PageSettings.HardMarginY, 75, 75) |
ergänzen, sehen Sie sofort die Auswirkungen.
Auch mit diesen Eigenschaften habe ich Versuche durchgeführt. Das Ergebnis war positiv. Während es mit dem .NET Framework 1.0/1.1 ein Balanceakt war, die möglichst optimalen Einstellungen für die Seitenränder zu finden, bieten die drei neuen Eigenschaften des PageSettings-Objekts anscheinend die Lösung der alten Problematik. Ohne allzu viel Platz unnötig zu verschwenden, können Sie den möglichen Druckbereich gut ausnutzen, ohne dabei Gefahr zu laufen, dass eventuell ein Teil des Drucks nicht zu Papier gebracht wird.
Sie können auch eine Standardvorgabe treffen und dem Anwender die Möglichkeit einräumen, selbst anhand von Versuchen die passendste Einstellung für die Seitenränder festzulegen. Da die Eigenschaften MarginBounds bzw. PageBounds schreibgeschützt sind, können diese nicht direkt verändert werden. Aber es bietet sich über die Eigenschaft DefaultPageSettings des PrintDocument-Objekts ein Weg an:
| Public Property DefaultPageSettings As PageSettings |
Das zurückgelieferte PageSettings-Objekt (siehe dazu auch Abschnitt 23.3) veröffentlicht die Eigenschaft Margin, das selbst die Eigenschaften Left, Right, Top und Bottom aufweist. Die Einheiten sind ebenfalls in 1/100 Zoll angegeben.
Wenn Sie beispielsweise den linken Rand auf eine Breite von 2 cm festlegen wollen, müssten Sie die folgende Anweisung implementieren:
| printDocument1.DefaultPageSettings.Margin.Left = 2 \ 0.0254 |
Mit den beiden Eigenschaften HasMorePages und Cancel des PrintPageEventArgs-Objekts kann ein Druckauftrag beendet werden, jedoch unter verschiedenen Voraussetzungen.
HasMorePages ist standardmäßig auf False gesetzt. Sollen mehrere Seiten ausgedruckt werden, muss der Wert auf True sein, damit der Ereignishandler noch einmal aufgerufen wird. Nach dem Druck der letzten Seite muss der Wert False sein. Das setzt natürlich voraus, dass im Programmcode ermittelt wird, ob noch eine weitere Seite zum Drucken ansteht. In Abschnitt 23.7 wird an einem Beispiel gezeigt, wie so etwas programmiert wird.
Cancel steht per Vorgabe False. Auf True gesetzt wird der Druckauftrag abgebrochen – unabhängig davon, wie viele Seiten noch in der Warteschlange stehen.
Das Graphics-Objekt des PrintDocument-Objekts ist ein anderes als das, das von der Form oder einer Picturebox im Paint-Ereignis bereitgestellt wird, obwohl beide funktionell gleich sind. Wenn Sie eine Grafik in einem Steuerelement ausgeben lassen und die Abbildung eventuell auch noch ausdrucken wollen, bietet es sich an, eine Methode zu schreiben, die für die Grafikausgabe sowohl im Steuerelement als auch für die Druckausgabe verantwortlich zeichnet. Das folgende Beispielprogramm zeigt, wie so etwas prinzipiell realisiert wird. Dazu wird ein einfaches Linienmuster nach dem Starten des Programms in einer Picturebox angezeigt. Nach dem Anklicken des Buttons wird die Grafik auf dem (Standard-)Drucker ausgedruckt.

Hier klicken, um das Bild zu Vergrößern
Abbildung 23.1 Ausgabe des Beispiels »EinfacherAusdruck«
| ' ---------------------------------------------------------- |
| ' Beispiel: ...\Kapitel 23\EinfacherAusdruck |
| ' ---------------------------------------------------------- |
| Public Class Form1 |
| Private Sub DrawGraphic(ByVal g As Graphics, _ |
| ByVal x1 As Integer, ByVal y1 As Integer, _ |
| ByVal x2 As Integer, ByVal y2 As Integer) |
| Dim p As Pen = New Pen(Color.Black) |
| For i As Integer = x1 To x2 Step 20 |
| g.DrawLine(p, x1, y1, i, y2) |
| Next |
| For i As Integer = x2 To x1 Step –20 |
| g.DrawLine(p, x2, y1, i, y2) |
| Next |
| End Sub |
| Private Sub PictureBox1_Paint(...) Handles PictureBox1.Paint |
| Me.DrawGraphic(e.Graphics, 0, 0, _ |
| PictureBox1.ClientSize.Width, _ |
| PictureBox1.ClientSize.Height) |
| End Sub |
| Private Sub btnDrucken_Click(...) Handles btnDrucken.Click |
| PrintDocument1.Print() |
| End Sub |
| Private Sub PrintDocument1_PrintPage(ByVal sender As Object, _ |
| ByVal e As PrintPageEventArgs) _ |
| Handles PrintDocument1.PrintPage |
| Me.DrawGraphic(e.Graphics, e.MarginBounds.X, _ |
| e.MarginBounds.Y, e.MarginBounds.Width_ |
| + e.MarginBounds.X, e.MarginBounds.Height + _ |
| e.MarginBounds.Y) |
| End Sub |
| End Class |
Die Routine, welche die Ausgabe der Grafik übernimmt, ist DrawGraphic. Diese Methode wird aus dem Paint-Ereignis der PictureBox und dem PrintPage-Ereignis des PrintDocument-Objekts aufgerufen. Damit die grafischen Methoden auch beim richtigen Empfänger, also der Picturebox oder dem Drucker, landen, muss die benutzerdefinierte Methode eine Referenz auf das Graphics-Objekt entgegennehmen, auf welche die Grafikroutinen aufgerufen werden.
Für die Grafikausgabe ist es wichtig, den oberen linken und den unteren rechten Eckpunkt festzulegen. Mit diesen Koordinaten muss DrawGraphic die Linien zeichnen. Bei der Picturebox werden die beiden Punkte durch (0, 0) und (pictureBox1.ClientSize.Width, pictureBox1.ClientSize.Height) beschrieben. Damit keine Linie des Ausdrucks abgeschnitten wird, habe ich die Eckpunkte des Ausdrucks mit den Eigenschaften X und Y von MarginBounds festgelegt. Mit VisibleClipBounds war die Ausgabe auf meinem Drucker auch nicht zu beanstanden und einwandfrei, aber das ist bekanntlich keine Garantie dafür, dass es bei Ihnen ebenso gut funktioniert.
| << zurück |
|
||||||||||||||
|
||||||||||||||
|
||||||||||||||
|
||||||||||||||
Copyright © Galileo Press 2007
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken.
Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die
gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich
geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung,
Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.